home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d17 / spool.arc / SPOOL.ASM < prev    next >
Assembly Source File  |  1986-02-01  |  39KB  |  1,074 lines

  1.     page    64,132
  2. ;----------------------------------------------------------------------------    
  3. ;    spooler program
  4. ;
  5. ;      modified by craig derouen 6-6-84
  6. ;
  7. ;      Version 2.0 by craig derouen 3-20-85
  8. ;            : change communications interrupt with buffer
  9. ;            : control to ioctl for better,more compatable
  10. ;            : operation. Change additional interrupt to user
  11. ;            : modifiable in case of conflicts.
  12. ;    Version 2.2 by Craig Derouen 4-4-85
  13. ;            : Change status return code so more compat with
  14. ;            : other programs. Add a pause feature. Add reprint
  15. ;            : last page feature.
  16. ;
  17. ; Configuring spooler:
  18. ;
  19. ;    Install the folowing line you CONFIG.SYS file on the boot
  20. ;    disk:
  21. ;              device=spool.dev [/option1] [/option2]
  22. ;
  23. ;     Where option may be the following:
  24. ;        Option 1:  "/1" -"/64" Decimal digit(s) indicating
  25. ;               (k)size of memory to reserve for print 
  26. ;               buffer.
  27. ;
  28. ;        Option 2:  "/L(1,2,3)" or "/C(1,2)". Specifies which
  29. ;               port is buffered, and becomes STANDARD
  30. ;               PRN output. Only one may be specified.
  31. ;               Option "L(1,2,3)" indicates LPT1,LPT2 or
  32. ;               LPT3 respectively. Option "/C(1,2)" indicates
  33. ;               Com1 or Com2 port. 
  34. ;
  35. ;    Thus if the following line is installed:
  36. ;
  37. ;            device = spool.dev /l2 /60
  38. ;
  39. ;    It means spool the PRN output to LPT2, reserve a 60K buffer.
  40. ;
  41. ;    Options are not case sensitive! Options may be installed in
  42. ;    any order. Any other characters are ignored. Default setup
  43. ;    is:
  44. ;        LPT1  and 1K buffer
  45. ;
  46.  
  47. user_int    equ    67h    ; Required additional interrupt. Just change
  48.                 ; it here if conflicts with anything.
  49. formfeed    equ    0ch    ; Form feed char. This is the char the code
  50.                 ; looks for to indicate new page
  51. ;----------------------------------------------------------------------------
  52. cseg    segment para public 'CODE'
  53.     assume    cs:cseg,es:cseg,ds:cseg
  54. ;----------------------------------------------------------------------------
  55. ;            device driver header
  56. ;----------------------------------------------------------------------------
  57. next_dev    dd    -1        ;pointer to next device
  58. attribute    dw      0C000h        ;character type device with ioctl
  59. strategy    dw    dev_strategy    ;pointer to device strategy
  60. interrupt    dw    dev_int        ;pointer to dev_int
  61. dev_name    db    'PRN     '    ;device indentifier
  62. ;-----------------------------------------------------------------------------
  63. ;         f u n c t i o n  t a b l e
  64. ;
  65. ;    this is the table of procedures which are called to service each type
  66. ; of device driver request from ms-dos.
  67. ;-----------------------------------------------------------------------------
  68. funtab        label    byte
  69.         dw    init        ;initialization routine
  70.         dw    exit        ;media check (block only)
  71.         dw    exit        ;build bpb     ""     ""
  72.         dw    ioctl_in    ;ioctl input
  73.         dw    exit        ;input (read)
  74.         dw    nd_input    ;non_destructive input no wait (char only)
  75.         dw    exit        ;input status
  76.         dw    exit        ;input flush
  77.         dw    output        ;output (write)
  78.         dw    output        ;output (write) with verify
  79.         dw    out_stat    ;output status
  80.         dw    out_flush    ;output flush
  81.         dw    ioctl_out    ;ioctl output
  82. ;-----------------------------------------------------------------------------
  83. ;        working variables for bufferring of output
  84. ;-----------------------------------------------------------------------------
  85. port_type    db    0        ;flag specifying lpt or com port - com=0, lpt=1
  86. rh_seg        dd    0        ;request header pointer - segment and offset
  87. data_seg    dw    0        ;data segment for printer data
  88. ending_address    dw    0        ; this is the value past back to dos from the initialization routine
  89. pull_ptr    dw    0        ;points to the current character to output from the buffer
  90. insert_ptr    dw    0        ;points place to insert next character into buffer
  91. buf_size    dw    0        ;size of the printer buffer in characters
  92. port_number    db    0        ;current port number of output port (0,1) if com, (0,1,2) if parallel
  93. move_cnt    dw    0        ;amount of data moved
  94. buf_flg        db    0        ;not zero if buffer full
  95. buff_cnt    dw    0        ;amount of data in the buffer
  96. loop_cnt    dw    0        ;number of times around the loop
  97. priority    dw    100        ;processing priority
  98. pointer_set    db    0        ;non-zero if irq0 vector modifyied
  99. ppause        db    0        ; flag for printer pause
  100. ;-----------------------------------------------------------------------------
  101. ;                device strategy routine
  102. ;
  103. ;    this procedure gets the request header from ms-dos and sets up rh_seg
  104. ; as the pointer used in the buffer driver for manipulation of the request
  105. ; header
  106. ;    entry:    ex:bx --> pointer to request header from ms-dos
  107. ;
  108. ;    exit:    rh_seg --> our internal pointer to request header
  109. ;-----------------------------------------------------------------------------
  110. dev_strategy    proc    far
  111.     mov    word ptr cs:[rh_seg],bx        ;save the request header segment
  112.     mov    word ptr cs:[rh_seg+2],es    ;save the request header offset
  113.     ret
  114. dev_strategy    endp
  115. ;------------------------------------------------------------------------------
  116. ;
  117. ;                device interrupt handler
  118. ;
  119. ;    this procedure is called each time ms-dos calls the driver.  its task
  120. ; is to branch control to the proper procedure to service the request.
  121. ;
  122. ;    this procedure saves all registers, uses rh_seg (pointer to request 
  123. ; header) to get the command number, then uses the command number as an offset
  124. ; into the command table (funtab) to jump to the appropriate procedure to service
  125. ; the request from ms-dos to the driver
  126. ;
  127. ;    entry:    rh_seg --> pointer to request header
  128. ;
  129. ;    exit:    cx --> number of bytes to transfer (read or write)
  130. ;        ex:di --> pointer to data (transfer address)
  131. ;        jump to proper procedure to service request, if valid, or
  132. ;        jump to ioctl_in if invalid command
  133. ;-----------------------------------------------------------------------------
  134. dev_int    proc    far
  135.     push    si
  136.     mov    si,offset funtab    ;point to the start of the function table
  137.     push    ax            ;save all registers onto the stack
  138.     push    bx
  139.     push    cx
  140.     push    dx
  141.     push    di
  142.     push    bp
  143.     push    ds
  144.     push    es
  145.     lds    bx,cs:rh_seg        ;get the request header segment
  146.     mov    cx,[bx+12h]        ;get the amount of data to transfer
  147.     mov    al,[bx+02h]        ;get the command byte
  148.     cbw                ;make 16 bit value
  149.     add    si,ax            ;add into our table value
  150.     add    si,ax            ;do it again
  151.     cmp    al,12            ;is it above the last entry in our table
  152.     ja    exit            ;do null action if so
  153.     les    di,[bx]+14d        ;get pointer to our data
  154.     push    cs            ;make our data segment register
  155.     pop    ds            ;the same as our code segment register
  156.     jmp    word ptr[si]        ;jump to correct action in the table
  157. ;-----------------------------------------------------------------------------
  158. ;            non destructive input routine
  159. ;
  160. ;    this procedure always returns done and busy to ms-dos to indicate that
  161. ; there is no character in the buffer to return.
  162. ;
  163. ;    entry:    rh_seg --> pointer to request header from ms-dos
  164. ;
  165. ;    exit:    rh_seg --> return request header with done and busy set in 
  166. ; status word, no other changes are made to the request header
  167. ;        ah --> 0011 (done and busy bits set)
  168. ;----------------------------------------------------------------------------
  169. nd_input:
  170.     mov    ah,03            ;indicate done and buzy to dos
  171.     jmp    short exit1        ;set our status word
  172. ;----------------------------------------------------------------------------
  173. ;                 dummy return point
  174. ;
  175. ;    this is the return procedure for exiting the driver and returning control
  176. ; to ms-dos.  the status word can be updated to indicate done and number of 
  177. ; characters processed.  the registers which were previously saved are restored
  178. ; prior to exiting.
  179. ;
  180. ;    entry:     ax,cx --> ah and al can be previously set as the status word 
  181. ; should be jmped to.
  182. ;
  183. ;    exit:    ds:bx --> pointer to update request header to return to ms-dos
  184. ;        es,ds,bp,di,dx,cx,bx,ax,si restored in that order
  185. ;-----------------------------------------------------------------------------
  186. exit:    mov    ah,01            ;indicate done for status word
  187.     mov    cx,cs:move_cnt        ;get the amount of data move
  188. exit1:    lds    bx,cs:rh_seg        ;load request header segment
  189.     mov    [bx+03],ax        ;save our exit status word
  190.     mov    [bx+12h],cx        ;save the amount of data read 
  191.     pop    es            ;restore the entry registers from the
  192.     pop    ds            ;stack before exiting
  193.     pop    bp
  194.     pop    di
  195.     pop    dx
  196.     pop    cx
  197.     pop    bx
  198.     pop    ax
  199.     pop    si
  200.     ret
  201. dev_int    endp
  202. ;-----------------------------------------------------------------------------
  203. ;                output status routine
  204. ;
  205. ;    this procedure returns status based on the amount of characters in the
  206. ; buffer.  if the buffer is full (buff_cnt = buf_size) then a jmp to nd_input
  207. ; is done to return busy and done to ms-dos, otherwise a jmp to exit is done
  208. ; to return done.
  209. ;
  210. ;    entry:    buff_cnt, buf_size are compared to see if the buffer is full
  211. ;
  212. ;    exit:    a jump is performed based on the amount of characters in the
  213. ; buffer.
  214. ;-----------------------------------------------------------------------------
  215. out_stat    proc    near
  216. out_stat1:mov    bx,buff_cnt        ;get amount of characters in the buffer
  217.     cmp    bx,buf_size        ;is it the same as our total buffer space
  218.     jnz    exit            ;indicate done to dos
  219.     jmp    nd_input        ;indicate buzy and done to the operating system
  220. out_stat    endp
  221. ;------------------------------------------------------------------------------
  222. ;                output routine
  223. ;
  224. ;    this procedure services all write requests from ms-dos.  this is done by
  225. ; inserting characters into the buffer until all characters have been inserted.
  226. ; each character is put into al and then insert is called which performs the
  227. ; insertion into the buffer.  this is performed repeatedly until all characters
  228. ; have been transferred into the buffer.
  229. ;
  230. ;    entry:    cx --> number of characters to transfer into the buffer
  231. ;        es:di --> pointer to data area of characters to transfer
  232. ;
  233. ;    exit:    move_cnt --> number of characters transferred into the buffer
  234. ;-----------------------------------------------------------------------------
  235. output    proc    near
  236.     sti                ;start interrupts just in case
  237. output1:cld                ;clear direction flag
  238.     mov    move_cnt,0        ;set number of characters accepted to zero
  239. output2:mov    al,es:[di]        ;get the character from requester
  240.     call    insert            ;insert the character into local buffer
  241.     inc    move_cnt        ;increment the amount of data moved
  242.     inc    di            ;bump the pointer to the next character
  243.     loop    output2            ;loop untill all data inserted into the buffer
  244.     jmp    exit            ;set status word to done and exit
  245. output    endp
  246. ;-----------------------------------------------------------------------------
  247. ;            insert character into printer buffer
  248. ;
  249. ;    this procedure performs the task of inserting characters into the buffer.
  250. ; the procedure does an idle loop while the buffer is full because the buffer is
  251. ; being emptied in a background method.  once there is room in the buffer, the
  252. ; insert_ptr is incremented to point to the next position.  if it points past
  253. ; the end of the buffer, it is set to point to the front of the buffer (a 
  254. ; circular queue).  once the correct insert point is established, the character
  255. ; is written to memory and the buffer count is incremented to indicate the
  256. ; insertion of the character.  interrupts are disabled for the short period
  257. ; when the character is actually written to memory and the buffer count is 
  258. ; incremented.
  259. ;
  260. ;    entry:    al --> character to insert into the buffer
  261. ;        buff_cnt --> number of characters currently in buffer
  262. ;        buff_size --> size of buffer, also is address of last character
  263. ;        in buffer
  264. ;        insert_ptr --> pointer to last character placed into buffer
  265. ;        data_seg --> data segment of buffer data
  266. ;    
  267. ;    exit:    insert_ptr --> pointer to character just inserted into buffer
  268. ;        buff_cnt --> updated number of characters in buffer
  269. ;        
  270. ;-----------------------------------------------------------------------------
  271.  
  272. insert    proc    near
  273. ;-----------------------------------------------------------------------------
  274. ; the following code needs to be checked to see if it is necessary (probably
  275. ;-----------------------------------------------------------------------------
  276.          cmp    pointer_set,0        ;it timer interrupt modifyed yet
  277.         jnz    insert1            ;continue if so
  278.         push    es            ;save current extra segment
  279.         mov    bx,0            ;set the segment address to zero
  280.         mov    es,bx            ;do it
  281.         mov    bx,20h            ;address of int vector 08
  282.         mov    word ptr es:[bx],offset prtout    ;set the print out address
  283.         mov    es:[bx+2],cs        ;set the segment
  284.         pop    es            ;restore our previos extra segment
  285.         mov    pointer_set,0ffh    ;set the pointer flag
  286. insert1:
  287.     mov    bx,buff_cnt        ;get the current buffer count
  288.     cmp    buf_size,bx        ;check for buffer full
  289.     jz    insert            ;loop untill space is available
  290.     push    ds            ;save data segment
  291.     push    ax            ;save the character onto the stack
  292.     inc    insert_ptr        ;bump insert pointer one position
  293.     mov    bx,buf_size        ;get the last position in the buffer
  294.     cmp    insert_ptr,bx        ;are they the same
  295.     jbe    insert2            ;continue if not
  296.     mov    insert_ptr,0        ;reset the pointer to begging of buffer
  297. insert2:mov    si,insert_ptr        ;get the current insert pointer
  298.     mov    ds,data_seg        ;get the data segment of our buffer
  299.     pop    ax            ;restore our character from the stack
  300.     cli                ;stop interrupts
  301.     mov    [si],al            ;put it into memory
  302.     pop    ds            ;restore our local data segment register
  303.     inc    buff_cnt        ;increment count of characters in buffer
  304.     sti                ;restart interrupts
  305.     ret
  306. insert    endp
  307. ;-----------------------------------------------------------------------------
  308. ;            flush buffer request routine
  309. ;
  310. ;    this procedure flushes the buffer by calling a procedure called flush.
  311. ; it then jmps to exit to set the status word to done and exits.
  312. ;-----------------------------------------------------------------------------
  313. out_flush    proc    near
  314.     call    flush            ;go flush contents of the memory buffer
  315.     jmp    exit            ;set status word to done and exit
  316. out_flush    endp
  317. ;-----------------------------------------------------------------------------
  318. ;            flush buffer routine
  319. ;
  320. ;     this is the procedure which actually performs the clearing of the buffer.
  321. ; interrupts are disabled during this action.  pull_ptr, insert_ptr, buff_cnt
  322. ; are all zeroed.  this sets the amount of characters in the buffer to zero,
  323. ; front of the buffer.
  324. ;
  325. ;    entry:    pull_ptr --> pointer to next character to send to printer
  326. ;        insert_ptr --> pointer to last character inserted into buffer
  327. ;        buff_cnt --> number of characters currently in buffer
  328. ;
  329. ;    exit:    pull_ptr, insert_ptr, buff_cnt --> all reset to zero (reset)
  330. ;-----------------------------------------------------------------------------
  331. flush    proc    near
  332.     cli                ;turn off interrupts while we work
  333.     mov    ax,0
  334.     mov    pull_ptr,ax        ;zero out the pull
  335.     mov    insert_ptr,ax        ;and insert pointers
  336.     mov    buff_cnt,ax        ;reset amount of data avail
  337.     sti                ;restart interrupts
  338.     ret
  339. flush    endp
  340. ;-----------------------------------------------------------------------------
  341. ;            buffer status routine entry point
  342. ;
  343. ;    this is the interrupt procedure which is vectored to by ioctl
  344. ; which was set up in init. the buffer status program  is used
  345. ; to perform io control functions of: flushing the buffer, getting and setting
  346. ; the port number, getting the buffer size, amount of characters in the buffer,
  347. ; and getting and setting the processing priority (background or foreground).
  348. ; since this status procedure is interrupt driven, it must save all registers,
  349. ; perform the desired operation, and return via an iret (interrupt return).
  350. ; the ax register, on entry, contains the request number.  it is doubled and
  351. ; used as an offset into a table to determine the address of the servicing 
  352. ; procedure.  on exit from the servicing procedure, bx contains the requested 
  353. ; information.
  354. ;
  355. ;    entry:    ax --> status request command number
  356. ;        
  357. ;    exit:    bx --> return value from status request servicing procedure
  358. ;            (buffer count, port number, etc.)
  359. ;-----------------------------------------------------------------------------
  360. ioctl_buf     struc
  361. ioctl_ifunct    dw    ?        ; the calling function
  362. ioctl_resp    dw    ?        ; any response from the routine
  363. ioctl_buf    ends
  364.  
  365. ioctl_in:
  366. ioctl_out:
  367.     mov    ax,es:[di.ioctl_ifunct]    ; get the function
  368.     mov    bx,es:[di.ioctl_resp]    ; get extended function
  369.     cmp    ax,10            ;test the request
  370.     jb    status1            ;continue if valid
  371.     mov    ax,1            ;change it to a number one request
  372. status1:add    ax,ax
  373.     mov    si,offset table        ;point to start of table
  374.     xchg    bx,ax            ;put in bx 
  375.     mov    si,[bx+si]        ;get routine address out of table
  376.     xchg    bx,ax            ;swap back around
  377.     call    si            ;call the requested routine
  378.     mov    es:[di.ioctl_resp],bx    ; put the results back
  379.     mov    al,0            ; no errors
  380.     jmp    exit
  381. ;-----------------------------------------------------------------------------
  382. ;            special action table
  383. ;
  384. ;    this is the table of procedures to service the status requests from 
  385. ; ioctl calls
  386. ;-----------------------------------------------------------------------------
  387. table    dw    flush            ;flush buffer
  388.     dw    get_port        ;go get the printer port number
  389.     dw    set_port        ;reassign printer port
  390.     dw    get_buf_siz        ;go get printer buffer size
  391.     dw    get_count        ;go get count of characters in buffer
  392.     dw    set_priority        ;set current processing priority
  393.     dw    get_priority        ;get current processing priority
  394.     dw    ident            ;return identity code to verify us
  395.     dw    pause_prn        ;pause the printer if a 1
  396.     dw    reprint_page        ; move buffer pointer back to start of
  397.                     ; page
  398.  
  399. ;-----------------------------------------------------------------------------
  400. ;            reprint current page
  401. ;
  402. ;    This procedure will search bacwards through the buffer looking
  403. ; for a form feed character. This makes the assupmtion the user wishes to
  404. ; reprint the page he is on. It will make a saftey check to see buffer does
  405. ; not overflow. If no form feed found,it will just return with no pointer
  406. ; change
  407. reprint_page    proc    near
  408.     mov    si,pull_ptr        ; get current offset
  409.     push    ds
  410.     mov    ds,data_seg        ; buffer segment
  411. back_scan_loop:
  412.     cmp    byte ptr[si],formfeed    ; is it what we want?
  413.     je    page_restart
  414.     dec    si
  415.     jz    overflow_test
  416.     jmp    back_scan_loop
  417. overflow_test:                ; check for character only here
  418.     cmp    byte ptr[si],formfeed
  419.     je    page_restartl
  420.     pop    ds
  421. ; no form feed was found, just restore ds and skip out of here!
  422. no_page:
  423.     xor    bx,bx            ; nothing to report back
  424.     ret
  425. page_restart:
  426. ; update pointers
  427.     dec    si            ; point to form feed
  428. page_restartl:
  429.     pop    ds
  430.     mov    pull_ptr,si
  431.     jmp    short no_page
  432. reprint_page    endp
  433. ;-----------------------------------------------------------------------------
  434.  
  435. ;-----------------------------------------------------------------------------
  436. ;            get current port number
  437. ;
  438. ;     this procedure returns the current port number in the bl register as an
  439. ; ascii digit 1-4 (31h-34h).
  440. ;
  441. ;    entry:    port_number --> current port number the buffer is assigned to
  442. ;
  443. ;    exit:    bl --> ascii digit of the current buffer port number
  444. ;        bh := port type. 0 com, 1 parallel
  445. ;-----------------------------------------------------------------------------
  446. get_port proc    near
  447.     xor    bx,bx            ;clear out bx
  448.     mov    bl,port_number        ;get the printer port in use
  449.     mov    bh,[port_type]
  450.     ret
  451. get_port    endp
  452. ;-----------------------------------------------------------------------------
  453. ;            get current buffer size
  454. ;
  455. ;    this procedure returns the current buffer size (capacity) in the bx
  456. ; register.  it is in the range of 0 to 65535.
  457. ;
  458. ;    entry:    buf_size --> assigned capacity of the buffer 
  459. ;
  460. ;    exit:    bx --> assigned capacity of the buffer (0 - 65535)
  461. ;-----------------------------------------------------------------------------
  462. get_buf_siz    proc    near
  463.     mov    bx,buf_size        ;load value of our buffer size
  464.     ret
  465. get_buf_siz    endp
  466. ;-----------------------------------------------------------------------------
  467. ;            identity
  468. ;
  469. ;    this procedure just returns a 16 bit id code saying we are
  470. ; spooler interrupt.
  471. ;
  472. ;-----------------------------------------------------------------------------
  473. ident    proc    near
  474.     mov    bx,55aah        ; a checkerboard
  475.     ret
  476. ident    endp
  477. ;-----------------------------------------------------------------------------
  478. ;             reassign port routine
  479. ;
  480. ;    this procedure sets the bufferred port number to the value received in
  481. ; the bl register from the int 65h.
  482. ;
  483. ;    entry:    bl --> new port number for bufferring (0,1) if com (0,1,2) if parallel
  484. ;        bh = port type. 0 com, 1 for parallel
  485. ;
  486. ;    exit:    port_number --> updated to new port number
  487. ;-----------------------------------------------------------------------------
  488. set_port    proc    near
  489.     mov    port_number,bl        ;save the new port number
  490.     mov     [port_type],bh
  491.     ret
  492. set_port    endp
  493. ;-----------------------------------------------------------------------------
  494. ;         get count of characters in printer buffer
  495. ;
  496. ;    this procedure returns the amount of characters currently in the buffer
  497. ; waiting for output to the designated port.
  498. ;
  499. ;    entry:    buff_cnt --> current amount of characters in buffer
  500. ;
  501. ;    exit:    bx -->    current amount of characters in buffer returned
  502. ;-----------------------------------------------------------------------------
  503. get_count    proc    near
  504.     mov    bx,buff_cnt        ;get amount of data in memory buffer
  505.     ret
  506. get_count    endp
  507. ;-----------------------------------------------------------------------------
  508. ;            set processing priority
  509. ;
  510. ;    this procedure sets the processing priority.  the priority dictates 
  511. ; how the character-output-to-the-port procedure services the output.  the
  512. ; priority is the maximum number of times the output procedure will loop 
  513. ; waiting for the port to become ready (not busy).  a low priority will only
  514. ;
  515. ;    entry:    bx --> new priority number
  516. ;
  517. ;    exit:    priority --> updated priority number for use by the buffer
  518. ;-----------------------------------------------------------------------------
  519. set_priority    proc    near
  520.     mov    priority,bx        ;save the new priority
  521.     ret
  522. set_priority    endp
  523. ;-----------------------------------------------------------------------------
  524. ;            get processing priority
  525. ;
  526. ;    this procedure returns the current processing priority in the bx
  527. ; register.
  528. ;
  529. ;    entry:    priority --> current processing priority
  530. ;
  531. ;    exit:    bx --> returned processing priority
  532. ;-----------------------------------------------------------------------------
  533. get_priority    proc    near
  534.     mov    bx,priority        ;get the current processing priority
  535.     ret
  536. get_priority    endp
  537. ;-----------------------------------------------------------------------------
  538. ;              handle pause control of printer output
  539. ;
  540. ;    This procedure will set pause on printer output,or turn it off.
  541. ;    Also returns status of pause switch in bl
  542. ;    
  543. ; (BX)    entry:    0  -------> Do nothing, just set status
  544. ;        1  -------> Turn on pause
  545. ;        2  -------> Turn off pause (print)
  546. ;
  547. ; (BL)    exit:    0  -------> Printer running
  548. ; (BL)      -1 -------> Printer is paused
  549. ;-----------------------------------------------------------------------------
  550. pause_prn    proc    near
  551.     cmp    bx,0
  552.     je    pstat_ret
  553.     cmp    bx,2
  554.     ja    pstat_ret
  555.     je    off_pause
  556. on_pause:
  557.     mov    byte ptr ppause,-1
  558.     jmp    short pstat_ret
  559. off_pause:
  560.     mov    byte ptr ppause,0
  561. pstat_ret:
  562.     mov    bl,byte ptr ppause
  563.     xor    bh,bh
  564.     ret
  565. pause_prn    endp    
  566. ;-----------------------------------------------------------------------------
  567. ;        parallel interrupt intercept routine
  568. ;
  569. ;    this procedure is set-up as the new parallel printer interrupt routine.
  570. ; when an interrupt occurs, control is diverted to this routine.  a check is 
  571. ; performed to see if the port being output to is the port we have set-up a
  572. ; buffer for.  if it is not, then the regular, old ibm bios routine is called.
  573. ; we re-vectored the old ibm bios routine to int 67h (pretty slick, huh?).
  574. ; then a test is done to see if the desired action is to output a character, 
  575. ; initialize the port, or get the status of the port.  
  576. ; procedure.
  577. ; if the request is for a port status, our procedure checks to see if the 
  578. ; buffer is full, if it is full, we return busy and selected in the ah status
  579. ; register.  if the buffer is not full, we return not busy and selected.
  580. ; if the request is to print a character in al, all registers are saved,
  581. ; the insert procedure is called to insert the character in the buffer, and
  582. ; a status check is performed for return from the interrupt.
  583. ;
  584. ;    entry:    ah --> interrupt request type (0,1,2)
  585. ;        al --> character to output
  586. ;        dx --> port number to work with (status, output, etc)
  587. ;        port_number --> the currently bufferred output port
  588. ;        buff_cnt --> current number of characters in the buffer
  589. ;        buf_size --> current capacity of the buffer
  590. ;
  591. ;    exit:    ah --> port status returned
  592. ;-----------------------------------------------------------------------------
  593. par_incep    proc    near
  594.     sti                ;restart interrupts
  595.     cmp    cs:[port_type],1    ; parallel=1, com=0
  596.     jnz     par_incep9
  597.     cmp    dl,cs:port_number    ;is it the port we are doing spooling for
  598.     jnz    par_incep9        ;transfer control to rom bios if not
  599.     cmp    ah,1            ;is it a reset request
  600.     jz    par_incep1        ;wait for buffer empty and reset
  601.     cmp    ah,2            ;is it a status request
  602.     jz    par_incep2        ;make status determination
  603.     call    insert_a_char
  604. par_incep2:
  605.     push    ax            ;save inital register onto the stack
  606.     mov    ax,cs:buff_cnt        ;get current buffer count
  607.     cmp    ax,cs:buf_size        ;is buffer full ?
  608.     pop    ax            ;restore al from stack
  609.     jz    par_incep3        ;indicate buzy                *** what about the rest of the status like out of paper
  610.     mov    ah,10h            ;indicate selected
  611.     iret
  612. par_incep3:
  613.     mov    ah,10h            ;indicate selected and buzy
  614.     iret
  615. par_incep1:
  616.     cmp    cs:buff_cnt,0        ;is buffer empty
  617.     jnz    par_incep1        ;loop untill it is
  618. par_incep9:
  619.     int    67h            ;hand control over to the rom bios
  620.     iret                ;return to calling routine
  621. par_incep    endp
  622.  
  623. ;--------------------------------------------------------------------
  624.  
  625. com_incep    proc
  626. ; this routine will replace the ibm int 14h for rs232 communication.
  627.     sti
  628.     
  629.     cmp cs:[port_type], 0        ; skip this routine if flash prn is using parallel
  630.     jnz com_incep9
  631.     
  632.     cmp cs:[port_number], dl    ; skip this routine if flash prn is using different com ports
  633.     jnz com_incep9    
  634.     
  635.     cmp ah, 0            ; skip if they want to set baud rate, etc
  636.     jz com_incep9
  637.     
  638.     cmp ah, 1            ; insert a char in the buffer
  639.     jz com_incep1
  640.     
  641.     cmp ah, 2            ; get a char (set error bits and return)
  642.     jz com_incep2
  643.     
  644.     cmp ah, 3            ; status
  645.     jz com_incep9
  646.     
  647.     iret
  648.     
  649. com_incep1:
  650.     call insert_a_char
  651.     push dx
  652.     call get_port_address
  653.     call get_com_status
  654.     pop dx
  655.  
  656.     push ax
  657.     mov ax,cs:buff_cnt    ;if the buffer is full set the high bit of ah
  658.     cmp ax,cs:buf_size
  659.     pop ax
  660.     jnz c1
  661.     or ah, 80h
  662. c1:
  663.     iret
  664.  
  665. com_incep9:
  666.     int 66h
  667.     iret
  668. com_incep2:            ; set all the error bits
  669.     mov ah, 1001111b
  670.     iret
  671. com_incep    endp
  672.         
  673. ;--------------------------------------------------------------------
  674.  
  675. insert_a_char    proc
  676.  
  677.     push    ax
  678.     push    bx
  679.     push    si
  680.     push    ds
  681. ;-----------------------------------------------------------------------------
  682. ;            establish local addressing
  683. ;    this is an important section because it sets-up the correct data 
  684. ; segment for the buffer prior to calling insert to place the character in al
  685. ; into the buffer.
  686. ;-----------------------------------------------------------------------------
  687.     push    cs
  688.     pop    ds
  689.     call    insert            ;insert the character into the printer buffer
  690.     pop    ds
  691.     pop    si            ;restore saved registers
  692.     pop    bx            ;from the stack
  693.     pop    ax
  694.     ret
  695. insert_a_char    endp
  696.  
  697. ;-----------------------------------------------------------------------------
  698. ;            dummy farjump procedure
  699. ;     this procedure is initially a do-nothing procedure.  but, after init
  700. ; gets done with it, it is replaced by the ibm rom bios timer interrupt routine.
  701. ; (check out the jmp farjmp instruction at the label prtout9:).  the farjmp
  702. ; label is replaced by init with the address of the timer interrupt routine.
  703. ; that way we can output a character from the buffer to the printer port and 
  704. ; then service the timer interrupt in the normal fashion using the same ibm
  705. ; bios routine (another slick move!!!).
  706. ;-----------------------------------------------------------------------------
  707. ;    farjmp    proc    far
  708. ;        ret
  709. ;        farjmp    endp
  710. ;-----------------------------------------------------------------------------
  711. ;            printer output routine
  712. ;
  713. ;    this is the procedure that replaces the standard timer interrupt.  that
  714. ; way whenever the timer is interrupted we can try to get a character out of
  715. ; the buffer to the output port.  a neato trick is that the standard timer
  716. ; interrupt code is jmped to at the very end of this code.  this way the 
  717. ; standard code is executed after ours (no applause, please!).  
  718. ; an important item to take note of is the fact that the data segment is 
  719. ; restored from the code segment prior to calling chrout.  the code segment
  720. ; stays the same throughout the driver.
  721. ;-----------------------------------------------------------------------------
  722. prtout    proc    near
  723.     sti                ;restart interrupts for other activitys
  724.     push    ax            ;save the registers we will use
  725.     push    bx
  726.     push    dx
  727.     push    si
  728.     push    ds
  729.     push    es
  730.     push    cs
  731.     pop    ds
  732.     call    chrout            ;do character out processing
  733.     pop    es
  734.     pop    ds
  735.     pop    si
  736.     pop    dx
  737.     pop    bx
  738.     pop    ax
  739. prtout9:db 0eah,0,0,0,0            ;far jump to old timer interrupt routine
  740. prtout    endp
  741. ;-----------------------------------------------------------------------------
  742. ;            printer port character output routine
  743. ;
  744. ;    this procedure handles removing a character from the buffer and 
  745. ; outputting it to the designated port.  alot of activities happens in this
  746. ; routine: buffer manipulation, status checking on the desired port and finally
  747. ; outputting the character to the data port.  
  748. ; the time-out counter (loop_cnt) is initialized to the processing priority.
  749. ; really it is a counter that controls how many times to loop until the 
  750.     
  751. chrout    proc    near
  752.     cmp    byte ptr ppause,-1    ; are we paused ?
  753.     jz    chrout9            ; then skip it for now!
  754.     mov    ax,priority        ;get current priority count
  755.     mov    loop_cnt,ax        ;set number of times to loop
  756. chrout1:
  757.     cmp    buff_cnt,0        ;is the buffer empty
  758.     jz    chrout9            ;exit if so
  759.     call    get_port_address
  760.     call    busytest
  761.     jc    chrout7
  762.     inc    pull_ptr        ;bump the pull pointer one chr
  763.     mov    bx,buf_size        ;get max buffer size
  764.     cmp    pull_ptr,bx        ;test for overflow
  765.     jbe    chrout2            ;continue if no problem
  766.     mov    pull_ptr,0h        ;reset pointer to begining of buffer
  767. chrout2:
  768.     mov    si,pull_ptr        ;get current pull pointer
  769.     mov    es,data_seg        ;get segment value of the data buffer
  770.     cli                ;turn off interrupts
  771.     mov    al,es:[si]        ;get character out of the buffer
  772.     mov     ah, al
  773.     dec    buff_cnt        ;adjust buffer count
  774.     call    outputal
  775.     sti
  776.     cmp    ah,1bh            ;was it some kind of control character
  777.     jb    chrout9            ;exit as there should be a delay comming
  778. chrout8:dec    loop_cnt        ;addjust the loop count
  779.     jnz    chrout1            ;loop if not done
  780. chrout9:ret
  781. chrout7:mov    ax,priority        ;get current priority
  782.     cmp    loop_cnt,ax        ;has it ever been ready
  783.     jnz    chrout8            ;continue if so
  784.     ret
  785. chrout    endp
  786.  
  787. ;--------------------------------------------------------------------
  788.  
  789. get_port_address    proc
  790. ; call: [port_type] = 0 com, 1 if parallel
  791. ;    [port_number] = 0, 1, 2
  792. ; return: dx = port address
  793.     push ax
  794.     push es
  795.     push si
  796.  
  797.     mov    ax,0040h        ;set extra segment to look
  798.     mov    es,ax            ;into the rombios data area
  799.     mov    si,8            ;load offset to par. printer table
  800.     cmp    cs:[port_type], 0
  801.     jnz    g1
  802.     mov     si, 0
  803. g1:
  804.     mov    al,cs:[port_number]    ;get the current port number
  805.     cbw                ;make it a 16 bit value
  806.     add    si,ax            ;do power of two
  807.     add    si,ax            ;to compute displacement into address table
  808.     mov    dx,es:[si]        ;get par. port address out of the table
  809.     
  810.     pop si
  811.     pop es
  812.     pop ax
  813.     ret
  814. get_port_address    endp
  815.  
  816. ;--------------------------------------------------------------------
  817.  
  818. busytest    proc
  819. ; call: dx = port address
  820. ;    [port_type] = 0 com, 1 par
  821. ; return: carry is set if a char. con not be output (busy).
  822.  
  823.     push dx
  824.     cmp [port_type], 1
  825.     jnz com_test
  826.     
  827.     inc    dx        ; parallel busy test
  828.     in    al,dx        
  829.     test    al,80h        
  830.     jz    busy_exit    
  831.     jmp not_busy_exit
  832. com_test:
  833.     add dx, 6        ; com busy test
  834.     in al, dx
  835.     test al, 20h
  836.     jz busy_exit
  837.     test al, 10h
  838.     jz busy_exit
  839.     dec dx
  840.     in al, dx
  841.     test al, 20h
  842.     jz busy_exit
  843.     jmp not_busy_exit
  844. busy_exit:
  845.     pop dx
  846.     stc
  847.     ret
  848. not_busy_exit:
  849.     pop dx
  850.     clc
  851.     ret
  852. busytest    endp
  853.  
  854. ;--------------------------------------------------------------------
  855.  
  856. outputal    proc
  857. ; output a character to the com or par. ports. assume the port is not busy.
  858. ; call:    dx = port address
  859. ;    [port_type] = 0 com, 1 par
  860. ;    al = character to output
  861.     
  862.     cmp [port_type], 1
  863.     jnz com_output
  864.     
  865.     out dx, al        ; parallel output (see ibm rom bios)
  866.     inc dx
  867.     mov al, 0dh
  868.     inc dx
  869.     out dx, al
  870.     mov al, 0ch
  871.     out dx, al
  872.     ret
  873. com_output:
  874.     push ax            ; com output (see ibm rom bios)
  875.     add dx, 4
  876.     mov al, 3
  877.     out dx, al
  878.     sub dx, 4
  879.     pop ax
  880.     out dx, al
  881.     ret
  882. outputal    endp
  883.     
  884. ;--------------------------------------------------------------------
  885.  
  886. get_com_status    proc
  887. ; see ibm rom bios page a-23
  888. ; call:    dx = port address of com
  889. ; return: ah = line status
  890. ;      al = modem status
  891.  
  892.     add dx, 5        ; point to the control port
  893.     in al, dx        ; line control status
  894.     mov ah, al
  895.     inc dx
  896.     in al, dx        ; modem status
  897.     ret
  898. get_com_status    endp
  899.  
  900. ;--------------------------------------------------------------------
  901.  
  902.     db 16 dup(?)
  903. ;
  904. ;    init routine
  905. ;
  906. init    proc    near
  907.     cld                ;clear direction
  908.     lds    si,rh_seg        ;get pointer to request header
  909.     lds    si,18[si]        ;get pointer to config message
  910. init1:    mov    bx,1            ;start with a value of one k
  911.     lodsb                ;get character
  912.     cmp    al,0dh            ;is it a return
  913.     jz    init3            ;exit determination if so
  914.     cmp    al,2fh            ;is it a slash seperating values 
  915.     jz    init2            ;if so get value
  916.     cmp    al,2dh            ;is it a dash character
  917.     jnz    init1            ;loop if no determination
  918. init2:    lodsb                ;get high order character
  919.     sub    al,30h            ;convert to binary
  920.     jb    init3            ;exit determination if not a digit
  921.     cmp    al,0ah            ;is if greater then the number 9
  922.     jnb    init3            ;exit if so
  923.     mov    bl,al            ;put value in bl
  924.     cmp    byte ptr[si],30h    ;check next character to see if an digit
  925.     jb    init3            ;not a digit go onto next test
  926.     lodsb                ;get the digit
  927.     sub    al,30h            ;convert to binary
  928.     jb    init3
  929.     cmp    al,0ah            ;check for greater then 9
  930.     jnb    init3            ;go onto next test if not
  931.     xchg    bx,ax            ;multiply orginal value by 10
  932.     mov    cl,0ah            ;value to multiply by
  933.     mul    cl            ;do it
  934.     add    al,bl            ;add in new digit
  935.     xchg    bx,ax            ;place in cx register
  936. init3:    cmp    bx,63            ;is it greater then 64 k
  937.     jbe    init4            ;continue if so
  938.     mov    bx,63            ;fource to to 64k max
  939. init4:    mov    ax,1024            ;value for one k
  940.     mul    bx            ;compute total number of k
  941.     cmp    dx,+01            ;check for 16 bit over flow
  942.     jb    init5
  943.     mov    ax,0ffffh        ;make a mask for 64 k
  944. init5:    mov    cs:buf_size,ax        ;save size of buffer
  945. ;
  946. ;    now check for printer port to use
  947. ;
  948. init5a:    lodsb                ;get next character in the string
  949.     cmp    al,0dh            ;is it the end of line
  950.     jz    init7            ;exit determination if so
  951.     cmp    al,2fh            ;is it a slash character that seperates values
  952.     jz    init6            ;continue if so
  953.     cmp    al,2dh            ;is it a dash that can seperate it to
  954.     jnz    init5a            ;ignore if not
  955. init6:    lodsb                ;get next character
  956.     and    al,0dfh            ;make it a upper case character
  957.     cmp    al,'C'            ;is it the letter "c" for com port
  958.     jnz    init10            ;if not "c" then test for "l"
  959.     mov    cs:[port_type],0    ;set port_type to com (value of 0)
  960.     jmp    init11            ;now go get port number 
  961. init10:    cmp    al,'L'            ;is it the letter "l" for lpt port
  962.     jnz    init7            ;exit if not a "l" or "c"
  963.     mov    cs:[port_type],1    ;set port_type to lpt (value of 1)
  964. init11:
  965.     lodsb                ;get next character, which should be the port number
  966.     sub    al,31h            ;convert to binary number
  967.     jb    init7            ;exit if less then the digit "1"
  968.     cmp    al,03            ;make sure not greater then "4"
  969.     jnb    init7            ;bypass if error
  970.  
  971.     call get_port_address    ; make sure the port is ready there
  972.     cmp dx, 0
  973.     jz init7
  974.  
  975.     ;    cbw                ;make 16 bit value
  976.     ;    push    ax            ;save the port number onto the stack
  977.     ;    add    ax,ax            ;double it for table lookup
  978.     ;    mov    bx,ax            ;put the table offset value into bx
  979.     ;    push    es            ;save our segment register
  980.     ;    mov    ax,0040h        ;set our segment value to rom bios area
  981.     ;    mov    es,ax            ;do it
  982.     ;    mov    di,0008*port_type    ;displacement into the bios area
  983.     ;    cmp    es:word ptr[bx+di],0    ;make sure the port really is there
  984.     ;    pop    es            ;restore our previos data segment
  985.     ;    pop    ax            ;restore port number from the stack
  986.     ;    jz    init7            ;use standard port value if not
  987.     
  988.     mov    cs:port_number,al     ;save the port number for future use
  989.     jmp    init8
  990. init7:    mov    cs:[port_type],1    ; lpt
  991.     mov    cs:port_number,0     ;fource port number to lpt1:
  992. init8:    mov    ax,cs            ;get value of current code segment
  993.     mov    ds,ax            ;set ds to point at code segment
  994. ;
  995. ;    get current interrupt vector for timer interrupt
  996. ;
  997.     push    es            ;save the segment register 
  998.     mov    ax,3508h        ;vector number for irq0
  999.     int    21h            ;get the vector
  1000.     mov    word ptr prtout9+1,bx    ;save the offset
  1001.     mov    word ptr prtout9+3,es    ;save the segment it will belong in
  1002.     pop      es            ;restore the extra segment register
  1003. ;
  1004. ;    setup interrupt vector 08h (timer) to print output routine
  1005. ;
  1006. ;    mov    ax,2508h        ;dos request
  1007. ;    mov    dx,offset prtout    ;pointer to our routine
  1008. ;    int    21h
  1009. ;
  1010. ;    get pointer to current parallel printer routine
  1011. ;
  1012.     push    ds            ;save our data segment onto the stack
  1013.     mov    ax,3517h        ;dos request
  1014.     int    21h
  1015. ;
  1016. ;    transfer it to int 67h vector for use by programs that want to
  1017. ;    use additional printers
  1018. ;
  1019.     push    es            ;save the segment address onto stack
  1020.     pop    ds            ;return it in data segment register
  1021.     mov    dx,bx            ;move offset to dx register
  1022.     mov    ah,25
  1023.     mov    al,user_int        ;dos request to init 67h (default)
  1024.     int    21h
  1025.     pop    ds            ;restore our local data segment
  1026. ;
  1027. ;    setup code to point parallel printer intercept routine
  1028. ;
  1029.     mov    ax,2517h        ;dos request
  1030.     mov    dx,offset par_incep    ;pointer to our routine
  1031.     int    21h
  1032.     
  1033.     push ds
  1034.     mov ah, 35h        ; get rs232_io vector and reassign it to vector 66h
  1035.     mov al, 14h
  1036.     int 21h            ; es:bx = vector
  1037.     push es
  1038.     pop ds
  1039.     mov dx, bx
  1040.     mov ah, 25h
  1041.     mov al, 66h
  1042.     int 21h
  1043.     pop ds
  1044.  
  1045.     mov ah, 25h        ; assign our com_incep routine to the old rs232_io int 14h
  1046.     mov al, 14h
  1047.     mov dx, offset com_incep
  1048.     int 21h
  1049. ;
  1050. ;    compute starting segment for the data buffer
  1051. ;
  1052.     mov    bx,offset init        ;point to the start of our init routine    
  1053.     mov    al,0fh            ;value to compute segment address
  1054.     and    al,bl            ;mask off bottom four bits
  1055.     jz    init9            ;allready on segment boundry
  1056.     add    bl,10h            ;bump lenght on one segment
  1057. init9:    mov    dx,bx            ;put value into dx
  1058.     mov    cl,04            ;amount to shift right
  1059.     shr    dx,cl            ;do it
  1060.     mov    ax,cs            ;get current code segment
  1061.     add    ax,dx            ;add to our segment length
  1062.     mov    data_seg,ax        ;save that as the start of our printer buffer
  1063.     mov    ax,buf_size        ;get the current buffer size
  1064.     add    ax,bx            ;add it to the code lenght
  1065.     mov [ending_address], ax
  1066.     lds    si,rh_seg        ;fill in the request header the point
  1067.     mov    [si+0eh],ax        ;past our useage
  1068.     mov    [si+10h],cs
  1069.     jmp    exit            ;set status word to done and exit
  1070. init    endp
  1071. cseg    ends
  1072.     end
  1073.  
  1074.